/*===============================================
Copyright (c): Technology Co.,Ltd. ALL rights reserved. 
                                                                 
  Create by: Lin
      Email:
       Date:
   Filename:
Description:
    Version:
Last Change:
                                                                 
=======================================*/
                                                                 
`ifndef MAC_DRIVER_SV
`define MAC_DRIVER_SV

`include "mac_seq_item.sv"

class mac_driver extends uvm_driver #(mac_seq_item);
	
	`uvm_component_utils(mac_driver)
	virtual interface mii_if vif;
	static int drv_packts_num = 0;

	extern function new(string name, uvm_component parent);
	extern function void build_phase(uvm_phase phase);
	extern function void connect_phase(uvm_phase phase);
	extern task reset_phase(uvm_phase phase);
	extern task main_phase(uvm_phase phase);
	extern task do_drive(input mac_seq_item mtrans);

endclass

function mac_driver::new(string name, uvm_component parent);
	super.new(name, parent);
endfunction

task mac_driver::reset_phase(uvm_phase phase);
	super.reset_phase(phase);
	`uvm_info(get_type_name(), "reset_phase", UVM_HIGH)

	vif.drv_clk.mii_tx_en <= 0;
	vif.drv_clk.mii_tx_data <= 0;

endtask

function void mac_driver::build_phase(uvm_phase phase);
	super.build_phase(phase);
endfunction

function void mac_driver::connect_phase(uvm_phase phase);
	super.connect_phase(phase);
	if (!uvm_config_db #(virtual mii_if #(PORT_NUM))::get(this, "", "vif", vif))
		`uvm_error("NOVIF", {"virtual interface must be set for: ", get_full_name(),".vif"})
endfunction

task mac_driver::main_phase(uvm_phase phase);
	`uvm_info(get_type_name(), "main_phase", UVM_HIGH)
	@(posedge vif.rst_n);
	forever begin
		seq_item_port.get_next_item(req);
		do_drive(req);
		seq_item_port.item_done();
	end
endtask

task mac_driver::do_drive(input mac_seq_item mtrans);
	byte unsigned data_q[];
	
	mtrans.pack_bytes(data_q);
	`uvm_info("TRACE", $sformatf("%m"), UVM_HIGH);
	`uvm_info(get_type_name(), {"req item\n", req.sprint}, UVM_HIGH)

	repeat(mtrans.delay_time) begin
		@(vif.drv_clk);
	end
	$display("\n\033[35m*******************************TIME:%8t*******************************", $time);
	$display("\033[35m*Packet[%0d] IN_PORT:[%0d], CRC_ERR is %0d, DV_ERR is %0d, LEN is %0d", ++drv_packts_num, req.port_num, req.crc_error, req.dv_error, req.data_size);
	$display("\033[35m*SMAC[48'h%12h] DMAC:[48'h%12h] Pload[0-1]: 16'h%h%h", req.source_mac_addr, req.destiny_mac_addr, req.pload[0], req.pload[1]);
	$display("\033[35m***************************************************************************\033[0m\n");
	req.pkt_id = drv_packts_num; 
	foreach (data_q[i]) begin
		@(vif.drv_clk)
		vif.drv_clk.mii_tx_data[mtrans.port_num] <= data_q[i][3:0];
		vif.drv_clk.mii_tx_en[mtrans.port_num] <= 1;
		@(vif.drv_clk)
		vif.drv_clk.mii_tx_data[mtrans.port_num] <= data_q[i][7:4];
		vif.drv_clk.mii_tx_en[mtrans.port_num] <= 1;
		@(posedge vif.mii_tx_clk)
		if (i == data_q.size() - 1) begin
			vif.drv_clk.mii_tx_en[mtrans.port_num] <= 0;
		end
		if (mtrans.dv_error == 1 && i == mtrans.frame_pre.size) begin
			vif.drv_clk.mii_tx_en[mtrans.port_num] <= 0;
			repeat(mtrans.delay_time) begin
				@(vif.drv_clk);
			end
		end
	end

endtask

`endif
